#include "rtda/heap/constant_pool.hpp"
#include "rtda/heap/field.h"
#include "rtda/heap/class.h"


namespace jvm {
namespace heap {

ConstantPool::ConstantPool(std::shared_ptr<Class> pClass) : m_pClass(pClass){}

std::shared_ptr<ConstantPool> ConstantPool::newConstantPool(std::shared_ptr<Class> pClass, const classfile::ConstantPool& cfCp)
{
    size_t cpCount = cfCp.size();
    auto ret = std::make_shared<ConstantPool>(pClass);
    ret->m_consts.resize(cpCount);

    for (size_t i = 1; i < cpCount; i++) {
        std::shared_ptr<classfile::ConstantInfo> pCpInfo = cfCp[i];
        if (!pCpInfo) continue;

        switch (pCpInfo->get_tag()) {
        case classfile::CONSTANT_TAG::INTEGER: {
            auto pIntInfo = std::dynamic_pointer_cast<classfile::ConstantIntegerInfo>(pCpInfo);
            if (pIntInfo)
                ret->m_consts[i] = std::make_pair(CONSTANT_TYPE::INT32, pIntInfo->get_value());
            else
                LOG_ERROR("type trans wrong!");

            break;
        }
        case classfile::CONSTANT_TAG::FLOAT: {
            auto pFloatInfo = std::dynamic_pointer_cast<classfile::ConstantFloatInfo>(pCpInfo);
            if (pFloatInfo)
                ret->m_consts[i] = std::make_pair(CONSTANT_TYPE::FLOAT, pFloatInfo->get_value());
            else
                LOG_ERROR("type trans wrong!");

            break;
        }
        case classfile::CONSTANT_TAG::LONG: {
            auto pLongInfo = std::dynamic_pointer_cast<classfile::ConstantLongInfo>(pCpInfo);
            if (pLongInfo)
                ret->m_consts[i] = std::make_pair(CONSTANT_TYPE::LONG, pLongInfo->get_value());
            else
                LOG_ERROR("type trans wrong!");

            i++; // Long takes two slots
            break;
        }
        case classfile::CONSTANT_TAG::DOUBLE: {
            auto pDoubleInfo = std::dynamic_pointer_cast<classfile::ConstantDoubleInfo>(pCpInfo);
            if (pDoubleInfo)
                ret->m_consts[i] = std::make_pair(CONSTANT_TYPE::DOUBLE, pDoubleInfo->get_value());
            else
                LOG_ERROR("type trans wrong!");

            i++; // Double takes two slots
            break;
        }
        case classfile::CONSTANT_TAG::STRING: {
            auto pStringInfo = std::dynamic_pointer_cast<classfile::ConstantStringInfo>(pCpInfo);
            if (pStringInfo)
                ret->m_consts[i] = std::make_pair(CONSTANT_TYPE::STRING, pStringInfo->get_string());
            else
                LOG_ERROR("type trans wrong!");

            break;
        }
        case classfile::CONSTANT_TAG::CLASS: {
            auto pClassInfo = std::dynamic_pointer_cast<classfile::ConstantClassInfo>(pCpInfo);
            if (pClassInfo)
                ret->m_consts[i] = std::make_pair(CONSTANT_TYPE::CLASS, ClassRef::newClassRef(ret, pClassInfo));
            else
                LOG_ERROR("type trans wrong!");

            break;
        }
        case classfile::CONSTANT_TAG::FIELDREF: {
            auto pFieldrefInfo = std::dynamic_pointer_cast<classfile::ConstantFieldRefInfo>(pCpInfo);
            if (pFieldrefInfo)
                ret->m_consts[i] = std::make_pair(CONSTANT_TYPE::FIELDREF, FieldRef::newFieldRef(ret, pFieldrefInfo));
            else
                LOG_ERROR("type trans wrong!");

            break;
        }
        case classfile::CONSTANT_TAG::METHODREF: {
            auto pMethodrefInfo = std::dynamic_pointer_cast<classfile::ConstantMethodRefInfo>(pCpInfo);
            if (pMethodrefInfo)
                ret->m_consts[i] = std::make_pair(CONSTANT_TYPE::METHODREF,MethodRef::newMethodRef(ret,pMethodrefInfo));
            else
                LOG_ERROR("type trans wrong!");

            break;
        }
        case classfile::CONSTANT_TAG::INTERFACE_METHODREF: {
            auto pInterfaceMethodrefInfo = std::dynamic_pointer_cast<classfile::ConstantInterfaceMethodRefInfo>(pCpInfo);
            if (pInterfaceMethodrefInfo)
                ret->m_consts[i] = std::make_pair(CONSTANT_TYPE::INTERFACE_METHODREF, InterfaceMethodRef::newInterfaceMethodRef(ret, pInterfaceMethodrefInfo));
            else
                LOG_ERROR("type trans wrong!");

            break;
        }
        default:
            // TODO: Handle other constant types
            break;
        }
    }

    return ret;
}

    std::shared_ptr<Class> ConstantPool::getClass() const { return m_pClass; }


} // namespace heap
} // namespace jvm